<template>
  <!-- webrtc播放器 -->
  <div class="video_box">
    <video :id="videoId" ref="videoRef" :controls="controls" style="width: 100%; height: 100%;"
      :style="{ 'object-fit': fit ? fit : 'fill' }" muted></video>
    <div v-if="isLoading" class="loading-overlay">{{ isToLoading ? '视频加载中' : '设备已离线' }}</div>
  </div>
</template>

<script lang="ts" setup name="webrtcPlayer">
import { onBeforeUnmount, onMounted, watch, ref } from 'vue';

const props = defineProps({ videoId: String, videoSrc: String, controls: Boolean, fit: { type: String, default: 'fill' }, isToLoading: { type: Boolean, default: true } });
let player = null;
const videoRef = ref(null);
let lastFrameTime = 0;
let lastFramesReceived = 0;
let pliRetryCount = 0;
let blackScreenRetryCount = 0;
const MAX_PLI_RETRIES = 3;
const MAX_BLACKSCREEN_RETRIES = 3;
const isLoading = ref(false);

const initVideo = (url) => {
  if (player) {
    player.pc.close();
    player = null;
  }
  console.log(props.videoId);
  let videoDom = document.getElementById(props.videoId);
  player = new ZLMRTCClient.Endpoint({
    element: videoDom,
    debug: false,
    zlmsdpUrl: url,
    simulcast: true,
    useCamera: true,
    audioEnable: true,
    videoEnable: true,
    recvOnly: true,
    resolution: {
      w: 600,
      h: 340
    },
    usedatachannel: true,
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, function (e) {
    console.error('ICE 协商出错: ' + props.videoId);
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, function (e) {
    videoDom.addEventListener('canplay', function (e) {
      console.log('播放成功: ' + props.videoId, e);
      isLoading.value = false;
      videoDom.play().catch(err => console.error('播放失败: ' + props.videoId, err));
    }, { once: true });
  });

  player.on(ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, function (e) {
    console.error('offer anwser 交换失败: ' + props.videoId, e);
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM, function (s) {
    console.log('获取到本地流: ' + props.videoId);
  });

  player.on(ZLMRTCClient.Events.CAPTURE_STREAM_FAILED, function (s) {
    console.error('获取本地流失败: ' + props.videoId);
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_CONNECTION_STATE_CHANGE, function (state) {
    console.log('当前状态: ' + props.videoId + ' ==> ' + state);
    if (state === 'disconnected' || state === 'failed') {
      hardRefreshPlayer();
    }
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_OPEN, function (event) {
    console.log('rtc datachannel 打开: ' + props.videoId, event);
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_MSG, function (event) {
    console.log('rtc datachannel 消息: ' + props.videoId, event.data);
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_ERR, function (event) {
    console.error('rtc datachannel 错误: ' + props.videoId, event);
  });

  player.on(ZLMRTCClient.Events.WEBRTC_ON_DATA_CHANNEL_CLOSE, function (event) {
    console.log('rtc datachannel 关闭: ' + props.videoId, event);
  });
};

const hardRefreshPlayer = () => {
  console.log("执行硬刷新: " + props.videoId);
  if (player) {
    player.pc.close();
    player = null;
  }
  const video = document.getElementById(props.videoId);
  if (video) {
    video.pause();
    video.srcObject = null;
    video.removeAttribute('src');
    video.load();
  }
  pliRetryCount = 0;
  blackScreenRetryCount = 0;
  isLoading.value = true;
  if (props.videoSrc) {
    setTimeout(() => {
      if (props.isToLoading) {
        initVideo(props.videoSrc)
      }
    }, 100);
  }
};

const stop = () => {
  let videoDom = document.getElementById(props.videoId);
  if (videoDom) videoDom.pause();
  if (player) {
    player.pc.close();
    player = null;
  }
  isLoading.value = false;
};

const requestPLI = () => {
  if (!player?.pc) return;
  const sender = player.pc.getSenders().find(s => s.track?.kind === "video");
  if (sender) {
    const params = sender.getParameters();
    if (!params.encodings) params.encodings = [{}];
    sender.setParameters(params).then(() => {
      console.log('已请求关键帧: ' + props.videoId);
      pliRetryCount++;
    }).catch(e => console.error('PLI 请求失败: ' + props.videoId, e));
  }
};

const checkVideoActive = async () => {
  const video = document.getElementById(props.videoId) as HTMLVideoElement;
  if (!video || !player?.pc) {
    console.log("检测到黑屏（无视频或无连接），尝试恢复: " + props.videoId);
    isLoading.value = true;
    blackScreenRetryCount++;
    if (blackScreenRetryCount < MAX_BLACKSCREEN_RETRIES) {
      requestPLI();
      setTimeout(() => video.play().catch(e => console.error("播放失败: " + props.videoId, e)), 100);
    } else {
      console.log('黑屏恢复多次失败，执行硬刷新: ' + props.videoId);
      hardRefreshPlayer();
    }
    return;
  }

  try {
    const stats = await player.pc.getStats();
    let framesReceived = 0;
    let packetsLost = 0;
    let bytesReceived = 0;
    let connectionState = player.pc.connectionState;
    stats.forEach(report => {
      if (report.type === 'inbound-rtp' && report.kind === 'video') {
        framesReceived = report.framesReceived || 0;
        packetsLost = report.packetsLost || 0;
        bytesReceived = report.bytesReceived || 0;
      }
    });

    // 黑屏检测：无视频尺寸或无数据流入
    if (video.videoWidth === 0 || bytesReceived === 0) {
      console.log(`检测到黑屏（videoWidth: ${video.videoWidth}, bytesReceived: ${bytesReceived}），尝试恢复: ` + props.videoId);
      isLoading.value = true;
      blackScreenRetryCount++;
      if (blackScreenRetryCount < MAX_BLACKSCREEN_RETRIES) {
        requestPLI();
        setTimeout(() => video.play().catch(e => console.error("播放失败: " + props.videoId, e)), 100);
      } else {
        console.log('黑屏恢复多次失败，执行硬刷新: ' + props.videoId);
        hardRefreshPlayer();
      }
      return;
    }

    // 画面冻结检测
    const currentTime = video.currentTime;
    if (currentTime === lastFrameTime && framesReceived === lastFramesReceived) {
      console.log('检测到画面冻结: ' + props.videoId);
      if (pliRetryCount < MAX_PLI_RETRIES) {
        requestPLI();
      } else {
        console.log('关键帧请求多次无效，执行硬刷新: ' + props.videoId);
        hardRefreshPlayer();
      }
    } else {
      pliRetryCount = 0;
      blackScreenRetryCount = 0;
      isLoading.value = false;
    }

    if (packetsLost > 10) {
      console.log('检测到高丢包率，请求关键帧: ' + props.videoId);
      requestPLI();
    }

    lastFrameTime = currentTime;
    lastFramesReceived = framesReceived;
  } catch (e) {
    console.error('获取WebRTC统计失败: ' + props.videoId, e);
  }
};

const interval = setInterval(async () => await checkVideoActive(), 2000);

onMounted(() => {
  watch(() => props.videoSrc, () => {
    if (props.videoSrc && props.isToLoading) {
      initVideo(props.videoSrc);
    } else {
      stop();
    }
  }, { immediate: true, deep: true });
});

onBeforeUnmount(() => {
  clearInterval(interval);
  if (player) {
    player.pc.close();
    player = null;
  }
});
</script>

<style>
.video_box {
  width: 100%;
  height: 100%;
  position: relative;
  user-select: none;
}

.loading-overlay {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  color: white;
  background: rgba(0, 0, 0, 0.7);
  /* z-index: 1; */
  font-size: 1.8vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>